<?php
// +----------------------------------------------------------------------
// | snake
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2022 http://baiyf.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: NickBai <1902822973@qq.com>
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\api\ApiHelper;
use app\common\service\MemberService;
use think\Db;

/**
 * API相关逻辑
 * 方法前缀带 _ 为内部方法，直接返回结果
 * Class ApiLogic
 * @package app\common\logic
 */
class ApiLogic extends BaseLogic
{
    private $isDebug = true;

    public function _getUserTokenAndUser($token)
    {
        $field[] = 'ut1.*';
        $field[] = 'u.account';
        $field[] = 'u.password';
        $field[] = 'u.pwd_salt';

        // 先找出该用户ID，然后按用户ID找出token列表，判断传入的token是否在最后一个

        $dataList = Db::name('UserToken')->alias('ut1')->field($field)
            ->join('UserToken ut2','ut1.user_id = ut2.user_id','LEFT')
            ->join('User u','u.id = ut1.user_id','LEFT')
            ->where('ut2.token', $token)->order('ut1.create_time DESC')->select();

        if(empty($dataList)){
            return [];
        }
        if(count($dataList) < 1){
            return [];
        }

        if ($dataList[0]['token'] == $token) {
            return $dataList[0];
        }
        else{
            return [];
        }
    }

    public function _getUserTokenAndUserAndVersion($token,$version)
    {
        $field[] = 'ut1.*';
        $field[] = 'u.mobile';
        $field[] = 'u.pwd';
        $field[] = 'u.salt';

        $where[] = ['ut2.token','=',$token];
        $where[] = ['ut2.version','=',$version];

        // 先找出该用户ID，然后按用户ID找出token列表，判断传入的token是否在最后一个

        $dataList = Db::name('UserToken')->alias('ut1')->field($field)
            ->join('UserToken ut2','ut1.user_id = ut2.user_id','LEFT')
            ->join('__MEMBER__ u','u.id = ut1.user_id','LEFT')
            ->where('ut2.token', $token)->order('ut1.create_time DESC')->select();

        if(empty($dataList)){
            return [];
        }
        if(count($dataList) < 1){
            return [];
        }

        if ($dataList[0]['token'] == $token) {
            return $dataList[0];
        }
        else{
            return [];
        }
    }

    public function _getLastUserTokenByUserId($userId){
        return Db::name('UserToken')->where('user_id', $userId)->order('id DESC')->find();
    }

    /**
     * 校验 token
     * @param $token
     * @param $version
     * @return array data 里面 包含  user_id  和 account
     * @throws \think\Exception
     * @throws \think\exception\DbException
     */
    public function checkToken($token,$version)
    {
        $model = $this->_getUserTokenAndUserAndVersion($token,$version);
        if(empty($model)){
            return $this->retError('token失效或超时，请重新登录',1001);
        }

        // 创建时间 + 过期秒数 大于 现在时间   说明还不过期
        if(($model['out_time']) > time()){
            return $this->retSuccess('正常',[
                'user_id' => $model['user_id'],
                'mobile' => $model['mobile'],
            ]);
        }
        else{
            return $this->retError('token失效或超时，请重新登录',1001);
        }
    }

    /**
     * 创建新的 token 一般登录时用
     * @param $userId
     * @param $version
     * @return array
     */
    public function makeToken($userId,$version)
    {
        $nowTime = time();
        // 过期时间
        $timeout = env('API_TOKEN_TIMEOUT');

        $tokenKey = env('API_TOKEN_KEY');
        $token = sha1($tokenKey . $userId . ($nowTime + $timeout));

        $data['user_id'] = $userId;
        $data['token'] = $token;
        $data['version'] = $version;
        $data['create_time'] = $nowTime;
        $data['out_time'] = $nowTime + $timeout;

        // 插入数据库
        $jieguo = Db::name('UserToken')->insertGetId($data);
        if($jieguo > 0){
            return $this->retSuccess('获取token成功',[
                'token' => $token,
                'expired' => ($timeout),
            ]);
        }
        else{
            return $this->retError('获取token失败',1002);
        }
    }

    /**
     * 清空 token 按 userId
     * @param $userId
     * @return array
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function clearTokenByUserId($userId)
    {
        if(!empty($userId)){
            Db::name('UserToken')->where('user_id', $userId)->setField('out_time', 0);
        }

        return $this->retSuccess('清除成功');
    }

    /**
     * 登录
     * @param string $mobile 手机号
     * @param string $password 密码
     * @param string $version 版本
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function login($mobile, $password,$version)
    {
        $memberService = new MemberService();
        $jieguo = $memberService->loginByMobileAndPwd($mobile, $password);
        $memberModel = $jieguo['data'];
        if($jieguo['err_code'] === 0){
            if (empty($memberModel)) {
                exceptionLogic('登录错误，请联系管理员',-1001);
            }
            // 生成token
            $jieguo = $this->makeToken($memberModel['id'],$version);
            if($jieguo['err_code'] !== 0){
                exceptionLogic('登录错误，token获取失败',-1002);
            }
            // 全部通过
            return $this->retSuccess('登录成功',[
                'version' => $version,                            // $version
                'token' => $jieguo['data']['token'],                            // token
                'expired' => $jieguo['data']['expired'],                        // token 过期时间
            ]);
        }
        else{
            // 如果 错误码小于0 为系统级错误，给用户统一返回错误代码
            if($jieguo['err_code'] < 0){
                exceptionLogic('',-2);
            }
            if($jieguo['err_code'] > 0){
                return $this->retError($jieguo['msg'],$jieguo['err_code']);
            }
            else{
                return $this->retError('登录失败，账号或者密码错误',1003);
            }
        }
    }

    /**
     * 添加请求日志
     * @param $row
     */
    public function addRequestLog($row)
    {
        $data = [
            'user_id' => $row['user_id'],
            'token' => $row['token'],
            'url' => $row['url'],
            'version' => $row['version'],
            'param' => $row['param'],
            'return' => $row['return'],
            'ip' => $row['ip'],
            'remark' => $row['remark'],
            'create_time' => time(),
        ];
        return db('RequestLog')->insertGetId($data);
    }

    /**
     * IP检测
     * @param $ip
     * @param $url
     * @param $version
     * @return bool false 不通过，true 通过
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function checkIpRules($ip, $url, $version)
    {
        // 列出所有该IP的数据
        $orm = Db::name('IpRules');
        $where[] = ['delete_time','<',1];
        $where[] = ['ip','=',$ip];
        $rules = $orm->where($where)->order('mode ASC,sort DESC')->cache(true)->select();
        $jieguo = null;
        // 判断 黑名单 全匹配的
        foreach ($rules as $rule){
            if(1 == $rule['mode'] && 1 == $rule['is_total']){
                $jieguo = false;
                break;
            }
        }
        // 判断 白名单 全匹配的
        foreach ($rules as $rule){
            if(2 == $rule['mode'] && 1 == $rule['is_total']){
                $jieguo = true;
                break;
            }
        }
        // 如果有白名单 直接返回
        if(true === $jieguo){
            return true;
        }

        $url = strtolower($url);
        $version = strtolower($version);
        // 否则 继续 按 url 和 版本判断

        // 黑名单
        foreach ($rules as $rule){
            if(1 == $rule['mode'] && $url == $rule['url'] && $version == $rule['version']){
                $jieguo = false;
                break;
            }
        }
        // 白名单
        foreach ($rules as $rule){
            if(2 == $rule['mode'] && $url == $rule['url'] && $version == $rule['version']){
                $jieguo = true;
                break;
            }
        }

        if (null == $jieguo) {
            // 找不到规则，默认通过
            return true;
        }
        else{
            return $jieguo;
        }
    }

    public function bindPush($token,$version,$cid,$osName = ''){
        $model = $this->_getUserTokenAndUserAndVersion($token,$version);
        if(empty($model)){
            return $this->retError('token失效或超时，请重新登录',1001);
        }

        $jieguo = Db::name('UserToken')->where('id','=',$model['id'])
            ->setField([
                'push_client_id' => $cid,
                'system_os' => $osName,
            ]);

        if (false === $jieguo) {
            return $this->retError('绑定推送失败');
        }
        else{
            return $this->retSuccess();
        }
    }
}